package com.robot.service.impl;

import algorithm.AlgorithmCaller;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.robot.common.client.HttpClient;
import com.robot.common.enums.FileStateEnum;
import com.robot.common.enums.IsDeleteEnum;
import com.robot.common.enums.LLMResultEnum;
import com.robot.common.exception.LLMResultException;
import com.robot.common.utils.JsonUtils;
import com.robot.common.utils.MinioUtils;
import com.robot.dao.dto.FileDTO;
import com.robot.dao.dto.FileOverViewDTO;
import com.robot.dao.dto.IDDTO;
import com.robot.dao.entity.File;
import com.robot.dao.entity.Knowledge;
import com.robot.dao.feigndto.ragdto.FileDeleteRequest;
import com.robot.dao.feigndto.ragdto.ParsingApiResponse;
import com.robot.dao.feigndto.ragdto.ParsingRequest;
import com.robot.dao.mapper.FileMapper;
import com.robot.dao.mapper.KnowledgeMapper;
import com.robot.dao.vo.FileOverViewVO;
import com.robot.dao.vo.FileVO;
import com.robot.service.FileService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class FileServiceImpl implements FileService {
    //文件上传缓冲bucket
    private static final String BUFFER_ID = "1821091408614404171";
    private static final String BUFFER_BUCKET_NAME = "1274682200419205120";


    @Autowired
    private MinioUtils minioUtils;

    @Autowired
    private AlgorithmCaller algorithmCaller;

    @Autowired
    private FileMapper fileMapper;

    @Autowired
    private KnowledgeMapper knowledgeMapper;

    @Transactional
    @ApiOperation(value = "上传文件")
    public List<FileOverViewVO> upload(FileDTO fileDTO) throws IOException {
        String bucketName = null;
        Long knowledgeId = null;
        if (Objects.equals(fileDTO.getKnowledgeId(), "0")) {//没有专属知识库，先丢到缓冲区
            bucketName = BUFFER_BUCKET_NAME;
            knowledgeId = Long.valueOf(BUFFER_ID);
        } else {
            //检查桶（知识库）是否存在，不存在则创建
            bucketName = minioUtils.existBucketPartial(fileDTO.getMinioBucketName());
            knowledgeId = Long.valueOf(fileDTO.getKnowledgeId());
        }

        Map<Long, MultipartFile> multipartFiles = new HashMap<>();
        //将信息写入数据库
        for (MultipartFile multipartFile : fileDTO.getFiles()) {
            File file = new File();
            file.setFileName(multipartFile.getOriginalFilename());
            file.setFileSize(String.valueOf(multipartFile.getSize()));
            file.setFileState(FileStateEnum.Analysis.getCode());
            file.setIsDelete(IsDeleteEnum.EXIST.getValue());
            file.setKnowledgeId(knowledgeId);
            file.setMinioBucketName(bucketName);
            file.setFileWordNumber(0);//待解析
            file.setFileUrl("null");//外链待获取
            fileMapper.create(file);
            //minio中存储的文件名（主键ID_fileName）
            multipartFiles.put(file.getId(), multipartFile);
        }
        Map<Long, String> upload = minioUtils.upload(bucketName, multipartFiles);

        //更新文件外链
        List<FileOverViewVO> files = new ArrayList<>();
        for (Map.Entry<Long, String> entry : upload.entrySet()) {
            Long fileId = entry.getKey();
            String fileUrl = entry.getValue();
            File file = new File();
            file.setFileUrl(fileUrl);
            file.setId(fileId);
            file.setFileName(multipartFiles.get(fileId).getOriginalFilename());
            fileMapper.update(file);

            FileOverViewVO fileOverViewVO = new FileOverViewVO();
            BeanUtils.copyProperties(file, fileOverViewVO);
            fileOverViewVO.setFileId(String.valueOf(fileId));
            fileOverViewVO.setMinioBucketName(bucketName);
//            fileOverViewVO.setKnowledgeId(fileDTO.getKnowledgeId());
            files.add(fileOverViewVO);

            Knowledge knowledge = knowledgeMapper.selectById(knowledgeId);
            knowledge.setFileNumber(knowledge.getFileNumber() + 1);
            knowledgeMapper.updateById(knowledge);

        }
        // 把文件传给算法端
        parsingFiles(files);
        return files;

    }

    public void parsingFiles(List<FileOverViewVO> files) throws IOException {
        //-----------------------------------------------
        List<ParsingRequest.File> fileList = new ArrayList<>();
        for (FileOverViewVO file : files) {

            ParsingRequest.File file1 = new ParsingRequest.File();
            file1.setId(file.getFileId());
            file1.setName(file.getFileName());
            file1.setUrl(file.getFileUrl());
            fileList.add(file1);
        }
        algorithmCaller.parsingFilesEmbedding(fileList);
    }


    /**
     * 根据文件ID 查询文件
     *
     * @param iddto
     * @return
     */
    public FileVO queryByFileId(IDDTO iddto) {
        File file = fileMapper.queryByFileId(Long.valueOf(iddto.getFileId()));

        LocalDateTime updateTime = file.getUpdateTime();
        long between = ChronoUnit.DAYS.between(updateTime, LocalDateTime.now());
        //todo 安全性（考虑反向代理）
        if (between >= 7) {//文件外链接过期,获取新链接
            String minioFileName = file.getId() + "-" + file.getFileName();
            String fileUrl = minioUtils.getPresignedObjectUrl(file.getMinioBucketName(), minioFileName);
            file.setFileUrl(fileUrl);
            fileMapper.updateById(file);
        }

        FileVO fileVO = new FileVO();
        BeanUtils.copyProperties(file, fileVO);
        fileVO.setFileId(String.valueOf(file.getId()));
        return fileVO;
    }

    /**
     * 删除文件（逻辑删除）
     *
     * @param iddto
     */
    public void delete(IDDTO iddto) {
        //step1 file表逻辑删除
        File file = new File();
        file.setId(Long.valueOf(iddto.getFileId()));
        file.setIsDelete(IsDeleteEnum.DELETED.getValue());
        fileMapper.update(file);

        //step2 算法删除文件
        ArrayList<String> fileList = new ArrayList<>();
        fileList.add(iddto.getFileId());
        ParsingApiResponse parsingApiResponse = algorithmCaller.deFilesContent(fileList);
        log.info("知识库文件删除——算法返回结果。。。。。。。：{}", JSONObject.toJSON(parsingApiResponse));

        //step3 更新知识库表字段，更新文件数量
//        if (parsingApiResponse.getCode() != LLMResultEnum.SUCCESS.getCode()) {
//            throw new LLMResultException(parsingApiResponse.getCode(), parsingApiResponse.getMessage());
//        }
        Knowledge knowledge = knowledgeMapper.selectById(iddto.getKnowledgeId());
        knowledge.setFileNumber(knowledge.getFileNumber() - 1);
        knowledgeMapper.updateById(knowledge);

    }

    /**
     * 更新文件状态
     *
     * @param fileOverViewDTO
     */
    public void updateFileState(FileOverViewDTO fileOverViewDTO) {
        File file = new File();
        file.setId(Long.valueOf(fileOverViewDTO.getFileId()));
        file.setFileState(fileOverViewDTO.getFileState());
        fileMapper.update(file);
    }

    @Override
    public void deleteknowledgefile(Long knowledgeId) {
        ParsingApiResponse parsingApiResponse=algorithmCaller.deFilesEmbedding(knowledgeId);
        if (parsingApiResponse.getCode() == LLMResultEnum.SUCCESS.getCode()) {
            fileMapper.deletebyknowledgeId(knowledgeId);
        } else {
            throw new LLMResultException(parsingApiResponse.getCode(), parsingApiResponse.getMessage());
        }
    }

    @Override
    public String getArticle(String MiniobucketName, String ArticleName) throws IOException {

        InputStream inputStream = minioUtils.getObject(MiniobucketName, ArticleName);
        String content = convertInputStreamToString(inputStream);
        return content;
    }

    private String convertInputStreamToString(InputStream inputStream) throws IOException {
        // 读取 InputStream 内容并转换为 String
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            return reader.lines().collect(Collectors.joining("\n"));
        }
    }
}
